#ifndef ROCA_H_
#define ROCA_H_

#include "displaylist.h"
#include "superficierev.h"
#include "discretizador.h"
#include "vertexs.h"
#include "textura.h"

#include "fisica/objeto.h"
#include "fisica/triangulomalla.h"

#include <btBulletDynamicsCommon.h>

class btCollisionShape;

class Roca : public DisplayList, public Fisica::Objeto {
   private:
      Fisica::TrianguloMalla mallaLateral;
      Fisica::TrianguloMalla mallaSuperior;

      Textura &textura;

      const Vertexs *vertexs_superficie;
      const Vertexs *vertex_tapa;

      float altura;

      void liberarRecursos() {
         if(vertexs_superficie) {
            delete vertexs_superficie;
            vertexs_superficie = 0;
         }
         if(vertex_tapa) {
            delete vertex_tapa;
            vertex_tapa = 0;
         }
      }

   public:
      /*
       * Se encarga de renderizar una roca, compuesta por una superficie curva
       * y una superficie plana a modo de tapa.
       * 
       * El parametro "superficie" representa una superficie curva que sera discretizada
       * por el objeto "disc".
       * El mimso discretizador sera usado para discretizar la tapa.
       * El renderizado sera mapeado usando la textura pasada.
       *
       * Tanto el objeto superficie como el discretizador no son utilizados por esta
       * instancia despues de finalizar su construccion por lo que pueden ser eliminados
       * luego de manera segura. Esto implica tambien que alguna modificacion a algunos
       * de estos parametros no afecta a la instancia Roca.
       *
       * Distinto es el parametro "textura" que debe existir al menos el tiempo que exista
       * esta instancia.
       *
       * Ninguno de los parametros sera apropiado por esta clase, por lo que deben ser
       * manejados por el usuario.
       *
       * La instancia Roca no solo discretiza y renderiza una roca, sino que ademas
       * almacena una copia de la discretizacion para reutilizarla posteriormente 
       * evitando recalcular la discretizacion.
       * Ademas, si es posible, almacena las operaciones de renderizado en una 
       * DisplayList reduciendo aun mas el tiempo de ejecucion.
       * */
      Roca(Textura &textura, const Superficie &superficie, 
            const Curva &revolucion,
            const float altura,
            const Discretizador &disc) :
         Objeto(0, 0, 0), 
         textura(textura), 
         vertexs_superficie(disc.superficie(superficie)),
         vertex_tapa(disc.curvaRellena(revolucion)),
         altura(altura) {

            for(size_t i  = 0; i < vertexs_superficie->cantGrupos(); ++i) {
               unsigned pos, cantCoords; 
               const std::vector<float> &data = vertexs_superficie->data(i, pos, cantCoords);
               mallaLateral.agregar(data, pos + 5, 8, cantCoords / 8, Fisica::TrianguloMalla::TriangleStrip);
            }

           for(size_t i  = 0; i < vertex_tapa->cantGrupos(); ++i) {
               unsigned pos, cantCoords; 
               const std::vector<float> &data = vertex_tapa->data(i, pos, cantCoords);
               mallaSuperior.agregar(data, pos + 5, 8, cantCoords / 8, Fisica::TrianguloMalla::TriangleFan);
            }

            btCompoundShape *compuesto = new btCompoundShape(true);

            btTransform transformacion;
            transformacion.setIdentity();
            transformacion.setOrigin(btVector3(0, 0, 0));
            compuesto->addChildShape(transformacion, &mallaLateral.makeForma());

            transformacion.setOrigin(btVector3(0, 0, altura));
            compuesto->addChildShape(transformacion, &mallaSuperior.makeForma());

            this->construirCon(*compuesto, 0);

            inicializar();
            if(esValido()) {
               liberarRecursos();
            }
         }

      virtual void ejecucion() const {
         textura.enlazar();

         glMatrixMode(GL_TEXTURE);
         glPushMatrix();
         glLoadIdentity();
         glScalef(10, 1, 1);

         glMatrixMode(GL_MODELVIEW);

         vertexs_superficie->enlazar();
         vertexs_superficie->dibujar();

         glPushMatrix();
         glTranslatef(0, 0, altura);

         glMatrixMode(GL_TEXTURE);
         glLoadIdentity();
         glMatrixMode(GL_MODELVIEW);

         vertex_tapa->enlazar();
         vertex_tapa->dibujar();

         glPopMatrix();

         glMatrixMode(GL_TEXTURE);
         glPopMatrix();
         glMatrixMode(GL_MODELVIEW);
         textura.desenlazar();
      }

      virtual ~Roca() {
         liberarRecursos();
      }
};

#endif
